﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;

namespace DDD {
    /// <summary>
    /// <see cref="Transformer"/>クラスに拡張メソッドを追加するクラス
    /// </summary>
    public static class TransformerExtensions {
        /// <summary>
        /// コンパイル
        /// </summary>
        /// <remarks>
        /// メモ：これって基底クラスのCompile()呼ばないで大丈夫？
        /// </remarks>
        /// <param name="msh"><see cref="Mesh"/>オブジェクト</param>
        public static void Compile (this Transformer msh) {
            if (msh.VertexBuffer == null || msh.Appearance == null) {
                throw new ArgumentNullException ("Submesh[0] is invalid(null)");
            } 
            var cache = Graphics3DExtensions.GetGLCache ();

            foreach(var m in msh.Transforms){
                var vbuf = m.VertexBuffer;
                var fbuf = m.FeedbackBuffer;
                var app = m.Appearance;
                var prog = app.ShaderProgram;

                app.Compile ();   // must be 1st
                vbuf.Compile (prog);
                fbuf.Compile (prog);
            }
        }

        /// <summary>
        /// レンダリング
        /// </summary>
        /// <param name="msh">メッシュ</param>
        /// <param name="node">カレントのノード</param>
        public static void Render (this Transformer msh, Node node) {
            if (msh.VertexBuffer == null || msh.Appearance == null) {
                throw new ArgumentNullException ("Submesh[0] is invalid(null)");
            } 
            var cache = Graphics3DExtensions.GetGLCache ();
            ErrorCode err;

            GL.Enable (EnableCap.RasterizerDiscard);

            foreach(var m in msh.Transforms){
                var fbuf = m.FeedbackBuffer;
                var vbuf = m.VertexBuffer;
                var app = m.Appearance;
                var sp = app.ShaderProgram;

                if (!sp.IsFeedbackEnabled) {
                    throw new InvalidOperationException ("No Feedback was set");
                }
                
                app.Render (node);   // must be 1st
                vbuf.Render ();
                fbuf.Render ();

                //var q = 0;
                //GL.GenQueries(1, out q);
                //GL.BeginQuery(QueryTarget.TransformFeedbackPrimitivesWritten, q);

                GL.BeginTransformFeedback (BeginFeedbackMode.Points);
                if ((err = GL.GetError ()) > 0) {
                    throw new ArgumentException ("glBeginTransformFeedback was failed, err=" + err);
                }
                GL.DrawArrays (BeginMode.Points, 0, vbuf.VertexCount);
                if ((err = GL.GetError ()) > 0) {
                    throw new ArgumentException ("glDrawArrays was failed, err=" + err);
                }
                GL.EndTransformFeedback ();

                //GL.EndQuery (QueryTarget.TransformFeedbackPrimitivesWritten);
                //var count = 0;
                //GL.GetQueryObject(q, GetQueryObjectParam.QueryResult, out count);

                //fbuf.PostRender ();
            }


            GL.Disable (EnableCap.RasterizerDiscard);

            // デフォルトに戻す
            // (注意)全部のステートを戻しているわけではない
            // (メモ)TransformFeedbackBufferをデフォルトに戻すのを忘れずに！
            GL.UseProgram (0);
            GL.BindVertexArray (0);
            GL.BindTransformFeedback (TransformFeedbackTarget.TransformFeedback, 0);
            GL.BindBuffer (BufferTarget.ElementArrayBuffer, 0);
            GL.ActiveTexture (TextureUnit.Texture0);

        }
    }
}
